import matplotlib.pyplot as plt


def func1(x):
    return (20 - 2 * x**2 - x**3) / 10


def func2(x):
    if (20 - 10 * x - 2 * x**2) >= 0:
        return pow(20 - 10 * x - 2 * x**2, 1.0 / 3)
    else:
        return -pow(-20 + 10 * x + 2 * x**2, 1.0 / 3)


def stef(f):
    return lambda x: x - (f(x) - x)**2 / (f(f(x)) + x - 2 * f(x))


def newton(x):
    return x - (x**3 + 2 * x**2 + 10 * x - 20) / (10 + 4 * x + 3 * x**2)


def iteration(f):
    """ iteration on function f """
    _x0: float = 1.36880810782137263522741433002
    # should be accurate enough
    _x = 1
    _error = []
    enough = False
    for i in range(30):
        _x = f(_x)
        _error.append(abs(_x - _x0))
        if (abs(_x - _x0) < 10**(-9)) and (enough is False):
            enough = True  # means the precision is enough
            print("The successful iteration time is {}.".format(i + 1))
    print(_error)
    return _error


"""iteration on func1"""
plt.plot(iteration(func1), "-d")
plt.yscale("linear")
plt.title("iteration on func1")
plt.show()
"""iteration on func2"""
plt.plot(iteration(func2), "-d")
plt.yscale("linear")
plt.title("iteration on func2")
plt.show()
"""iteration on steffensen func1"""
plt.plot(iteration(stef(func1)), "-d")
plt.yscale("log")
plt.title("iteration on steffensen func1")
plt.show()
"""iteration on steffensen func2"""
plt.plot(iteration(stef(func2)), "-d")
plt.yscale("log")
plt.title("iteration on steffensen func2")
plt.show()
"""iteration on newton's method"""
plt.plot(iteration(newton), "-d")
plt.yscale("log")
plt.title("iteration on newton's method")
plt.show()
